#pragma once
#include <iostream>
#include <string>
#include <errno.h>   
#include <string.h> 
#include "../testLOG/log.hpp"
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unordered_map>
#include <functional>
#define SIZE 1024

typedef std::function<std::string(std::string&)> func_t;

LOG log(PRINT_TO_SCREEN);

enum{
    SOCKET_ERR=1,
    BIND_ERR
};


class UdpServer
{
public:
    UdpServer(uint16_t port=1234,const std::string& ip="0.0.0.0")//设定为0.0.0.0，表示监听所有IP地址的请求
        :sockfd_(0), port_(port), ip_(ip), isrunning_(false)
    {}

    void Init()
    {
        // 1. 创建udp socket
        // 2. Udp 的socket是全双工的，允许被同时读写的
        sockfd_= socket(AF_INET, SOCK_DGRAM, 0); // PF_INET与AF_INET是等价的,类似于打开一个文件
        if(sockfd_ < 0)
        {
            log(FATAL, "socket create error, sockfd: %d", sockfd_);
            exit(SOCKET_ERR);
        }
        else 
        {
            log(INFO, "socket create success, sockfd: %d", sockfd_);
        }

        //创建本地地址结构体
        struct sockaddr_in local;
        memset(&local,0, sizeof(local)); 
        local.sin_family= AF_INET; // IPv4
        local.sin_port= htons(port_); // 将端口号转换为网络字节序(注意端口号是16位的，需要转为网络字节序，使用htons函数)
        local.sin_addr.s_addr= inet_addr(ip_.c_str()); // inet_addr会提取字符串中的IP地址，并转换为网络字节序的32位整数

        //进行绑定
        if(bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) < 0)
        {
            log(FATAL, "bind error, errno: %d, err string: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        else
        {
            log(INFO, "bind success, errno: %d, err string: %s", errno, strerror(errno));
        }
    }

    void CheckUser(const std::string& client_ip, uint16_t client_port, struct sockaddr_in& client_addr)
    {
        // 检查用户是否在线
        std::string key = "[" + client_ip + ":" + std::to_string(client_port) + "]";
        if(online_user.find(client_ip) == online_user.end())
        {
            online_user.insert({client_ip, client_addr}); // 如果用户不在线，则添加到在线用户列表
            std::cout<< key<<"add to online user list."<<std::endl;
        }
    }

    void BoradCast(const std::string& client_ip, uint16_t client_port, const std::string& msg)
    {
        std::string key = "[" + client_ip + ":" + std::to_string(client_port) + "]" + msg ;
        // 广播消息给所有在线用户
        for(const auto& user : online_user)
        {
            const std::string& user_ip = user.first;
            const struct sockaddr_in& user_addr = user.second;
            socklen_t len = sizeof(user_addr);
            sendto(sockfd_, key.c_str(), key.size(), 0, (struct sockaddr*)&user_addr, len);
        }
    }

    void Run(func_t func) 
    {
        isrunning_ = true;
        char input[SIZE]={0};
        while(isrunning_)
        {
            struct sockaddr_in client_addr;
            memset(&client_addr, 0, sizeof(client_addr));
            socklen_t len = sizeof(client_addr);
            int n = recvfrom(sockfd_, input, 1023, 0, (struct sockaddr*)&client_addr, &len);
            if(n < 0)
            {
                log(WARNING, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
                continue;
            }
            // cout<< "Received from client: " << input << std::endl;

            std::string client_ip = inet_ntoa(client_addr.sin_addr); // 获取客户端IP地址
            uint16_t client_port = ntohs(client_addr.sin_port); // 获取客户端端口号 
            CheckUser(client_ip, client_port,client_addr);
            
            // 将接收到的数据进行处理
            input[n] = '\0'; 
            std::string tmp=input;

            BoradCast(client_ip, client_port,tmp);
            // std::string rev= func(tmp); 
            // // cout<< "After processing: " << rev << std::endl;
            // sendto(sockfd_, rev.c_str(), rev.size(), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
        }
    }

    ~UdpServer()
    {
        if(sockfd_ > 0)
        {
            close(sockfd_);
        }
    }
private:
    std::string ip_;// IP地址
    int sockfd_; // 套接字描述符
    bool isrunning_; // 是否正在运行
    uint16_t port_; // 端口号
    std::unordered_map<std::string,struct sockaddr_in> online_user;
}; 